﻿#include "Exception.h"
#include "XyNet/Common/CrossObjectHolder.h"
#include "XyNet/Common/Logger.h"

namespace XyNet
{
	Exception::ExceptionHandler Exception::_exceptionHandler =
		bind(&Exception::defaultHandleException, _1);

	Exception::Exception(const string& message,
		const char* currentFunction, const char* file, long line)
	{
		if (currentFunction)
		{
			boost::format format("%s\nFunction: %s\nFile: %s\nLine: %d");
			format % message % currentFunction % file % line;
			_message = format.str();
		}
		else
		{
			_message = message;
		}
	}

	Exception::~Exception() {}

	const char* Exception::what() const throw()
	{
		return _message.empty() ? "Unknown exception" : _message.c_str();
	}

	void Exception::handleException(const exception& e)
	{
		_exceptionHandler(e);
	}

	void Exception::handleException(const exception& e, const char* currentFunction /*= nullptr*/,
		const char* file /*= nullptr*/, long line /*= 0*/)
	{
		boost::format format("Handle Exception: \nFunction: %s\nFile: %s\nLine: %d");
		format % currentFunction % file % line;
		Logger::getDefault()->logError(format.str());

		_exceptionHandler(e);
	}

	void Exception::defaultHandleException(const exception& e)
	{
		string message = typeid(e).name() + string(": ") + e.what();	// 这里才能获取子类
		Logger::getDefault()->logError(message);
	}

	void Exception::setExceptionHandler(const ExceptionHandler& handler)
	{
		_exceptionHandler = handler;
	}
}

//////////////////////////////////////////////////////////////////////////

// 异常函数不能抛出异常
namespace XyNet
{
	stack<string> _exceptionMessageStack;

	XYNET_API void HandleException(const exception& e)
	{
		_exceptionMessageStack.push(e.what());
	}

	XYNET_API void SetExternalExceptionHandler()
	{
		Exception::setExceptionHandler(&HandleException);
	}

	XYNET_API bool IsExceptionMessageStackEmpty()
	{
		return _exceptionMessageStack.empty();
	}

	XYNET_API string* PopExceptionMessage()
	{
		if (!IsExceptionMessageStackEmpty())
		{
			string* str = StringHold(_exceptionMessageStack.top());
			_exceptionMessageStack.pop();
			return str;
		}
		else
		{
			return nullptr;
		}
	}
}